/*    file: FrameToBitmap.cpp
 *    desc:
 * 
 * created: 2014-06-30 20:42:40
 *  author: zhengchuanjiang
 * version: 1.0
 * company: 
 */

#include "stdafx.h"
#include "FrameToBitmap.h"
#include <stdio.h>
#include <stdlib.h>

#ifdef WIN32

#else

#pragma pack(1)

typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int   DWORD;
typedef int	LONG;

typedef struct tagRGBQUAD {
	BYTE rgbBlue;
	BYTE rgbGreen;
	BYTE rgbRed;
	BYTE rgbReserved;
} RGBQUAD;

typedef struct tagBITMAPFILEHEADER {
    WORD bfType;
    DWORD bfSize;
    WORD bfReserved1;
    WORD bfReserved2;
    DWORD bfOffBits;
} BITMAPFILEHEADER,*LPBITMAPFILEHEADER,*PBITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER {
    DWORD biSize;
    LONG biWidth;
    LONG biHeight;
    WORD biPlanes;
    WORD biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    LONG biXPelsPerMeter;
    LONG biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
} BITMAPINFOHEADER,*LPBITMAPINFOHEADER,*PBITMAPINFOHEADER;

#pragma()

#define BI_RGB 	0

#endif //


bool rgb32FrameToBitmap(AVFrame* frame, const char* filename)
{
#define BFT_BITMAP 0x4d42   /* 'BM' */
#define DibNumColors(lpbi)      ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 \
    ? (int)(1 << (int)(lpbi)->biBitCount)          \
    : (int)(lpbi)->biClrUsed)

#define DibSize(lpbi)           ((lpbi)->biSize + (lpbi)->biSizeImage + (int)(lpbi)->biClrUsed * sizeof(RGBQUAD))

#define DibPaletteSize(lpbi)    (DibNumColors(lpbi) * sizeof(RGBQUAD))

    BITMAPFILEHEADER fileHeader;
    memset(&fileHeader, 0, sizeof(fileHeader));

    BITMAPINFOHEADER infoHeader;
    memset(&infoHeader, 0, sizeof(infoHeader));
    infoHeader.biSize = sizeof(infoHeader);
    infoHeader.biWidth = frame->width;
    infoHeader.biHeight = -frame->height;
    infoHeader.biPlanes = 1;
    infoHeader.biBitCount = 32;
    infoHeader.biCompression = BI_RGB;

    LPBITMAPINFOHEADER  pdib = (LPBITMAPINFOHEADER)&infoHeader;

    DWORD dwSize = DibSize(pdib);
    fileHeader.bfType          = BFT_BITMAP;
    fileHeader.bfSize          = dwSize + sizeof(BITMAPFILEHEADER);
    fileHeader.bfReserved1     = 0;
    fileHeader.bfReserved2     = 0;
    fileHeader.bfOffBits       = (DWORD)sizeof(BITMAPFILEHEADER) + pdib->biSize + DibPaletteSize(pdib);

    bool done = false;
    FILE* file = NULL;
    file = fopen(filename, "bw");
    if (file)
    {
        fwrite(&fileHeader, 1, sizeof(BITMAPFILEHEADER), file);
        fwrite(pdib, 1, infoHeader.biSize, file);
        fwrite(frame->data[0], 1, frame->linesize[0] * frame->height, file);
        fclose(file);
        done = true;
    }
    return done;
}

bool frameToBitmap(AVFrame* frame, const char* filename)
{
    if (!frame || !frame->width)
    {
        return false;
    }

    if (frame->format != AV_PIX_FMT_BGRA)
    {
        AVFrame* rgbFrame = av_frame_alloc();
        rgbFrame->width = frame->width;
        rgbFrame->height = frame->height;
        rgbFrame->format = AV_PIX_FMT_BGRA;
        av_frame_get_buffer(rgbFrame, 1);

        SwsContext* pContext = sws_getContext(frame->width,
            frame->height, (AVPixelFormat)frame->format,
            frame->width, frame->height,
            AV_PIX_FMT_BGRA, SWS_BILINEAR, 0, 0, 0);

        sws_scale(pContext, frame->data, frame->linesize, 0, frame->height,
                rgbFrame->data, rgbFrame->linesize);

        bool done = rgb32FrameToBitmap(rgbFrame, filename);

        sws_freeContext(pContext);

        av_frame_free(&rgbFrame);
        return done;
    }
    else
    {
        return rgb32FrameToBitmap(frame, filename);
    }
}




